<template>
  <el-container class="outer-container">
    <el-aside width="285px" class="simulated-sidebar">
      <div style="padding: 20px; text-align: center;">
        <p style="font-weight: bold; margin-bottom: 10px;">固定侧边栏</p>
        <p style="font-size: 0.9em;">(285px宽)</p>
        <p style="font-size: 0.9em;">模拟项目导航位置</p>
      </div>
    </el-aside>

    <el-container class="main-content-container">
      <el-aside width="400px" class="left-panel-aside">
        <el-card class="box-card" shadow="never">
          <template #header>
            <div class="card-header">
              <span>数字通道</span>
            </div>
          </template>
          <el-button type="primary" size="small" @click="clickGetDigitalChannelInfo" style="width: 100%; margin-bottom: 10px;">获取数字通道列表</el-button>
          <div class="digitaltdiv">
            <table id="digitalchannellist" class="digitalchannellist" cellpadding="0" cellspacing="0" border="0">
              </table>
          </div>
        </el-card>
      </el-aside>

  <el-main class="right-panel-main">
       <div class="video-player-wrapper" 
             @mouseenter="handleVideoContainerMouseEnter" 
             @mouseleave="handleVideoContainerMouseLeave">
          
          <div id="divPlugin" class="plugin">
            </div>

          <transition name="el-fade-in-linear">
            <div class="player-controls-bar" v-show="playerControls.show">
              <el-button 
                type="text" 
                icon="el-icon-video-pause" 
                class="control-button"
                title="停止预览"
                @click="stopCurrentWindowPreview"></el-button>
              
              <div class="volume-control">
                <el-button 
                  type="text" 
                  :icon="playerControls.isMuted ? 'el-icon-turn-off-microphone' : 'el-icon-microphone'" 
                  class="control-button"
                  :title="playerControls.isMuted ? '取消静音' : '静音'"
                  @click="toggleMute"></el-button>
                <el-slider 
                  v-model="playerControls.volume" 
                  :min="0" 
                  :max="100" 
                  @change="handleVolumeChange"
                  :show-tooltip="false"
                  class="volume-slider"></el-slider>
              </div>

              <div style="flex-grow: 1;"></div>

              <el-button 
                type="text" 
                icon="el-icon-full-screen" 
                class="control-button"
                title="全屏"
                @click="triggerFullScreen"></el-button>
            </div>
          </transition>
        </div>

        <el-card class="box-card login-card" shadow="never">
          <template #header>
            <div class="card-header">
              <span>登录</span>
            </div>
          </template>
          <el-form ref="loginFormRef" :model="loginForm" label-width="90px" size="small">
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="IP地址">
                  <el-input v-model="loginForm.ip" id="loginip"></el-input>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="端口号">
                  <el-input v-model="loginForm.port" id="port"></el-input>
                </el-form-item>
              </el-col>
            </el-row>
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="用户名">
                  <el-input v-model="loginForm.username" id="username"></el-input>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="密码">
                  <el-input v-model="loginForm.password" type="password" show-password id="password"></el-input>
                </el-form-item>
              </el-col>
            </el-row>
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="设备端口">
                  <el-input v-model="loginForm.devicePort" placeholder="可选" id="deviceport"></el-input>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="RTSP端口">
                  <el-input v-model="loginForm.rtspPort" placeholder="可选" id="rtspport"></el-input>
                </el-form-item>
              </el-col>
            </el-row>
            <el-form-item label="窗口分割">
              <el-button-group>
                <el-button size="small" :type="loginForm.wndNum === 1 ? 'primary' : 'default'" @click="setWndNum(1)">1x1</el-button>
                <el-button size="small" :type="loginForm.wndNum === 2 ? 'primary' : 'default'" @click="setWndNum(2)">2x2</el-button>
                <el-button size="small" :type="loginForm.wndNum === 3 ? 'primary' : 'default'" @click="setWndNum(3)">3x3</el-button>
                <el-button size="small" :type="loginForm.wndNum === 4 ? 'primary' : 'default'" @click="setWndNum(4)">4x4</el-button>
              </el-button-group>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="clickLogin" size="small">登录</el-button>
              <el-button @click="clickLogout" size="small">退出</el-button>
              <el-button type="info" plain @click="clickGetDeviceInfo" size="small">获取基本信息</el-button>
            </el-form-item>
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="已登录设备">
                  <el-select v-model="selectedDeviceIp" id="ip" placeholder="请选择" @change="handleDeviceChange" style="width: 100%;" size="small">
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="通道列表">
                  <el-select v-model="selectedChannel" id="channels" placeholder="请选择" style="width: 100%;" size="small">
                  </el-select>
                </el-form-item>
              </el-col>
            </el-row>
            <el-form-item>
              <el-button type="success" plain @click="clickStartRealPlay" size="small">开始预览</el-button>
              <el-button type="danger" plain @click="clickStopRealPlay" size="small">停止预览</el-button>
              <el-button type="warning" plain @click="setTextOverlay" size="small">设置文本叠加</el-button>
            </el-form-item>
          </el-form>
        </el-card>

        <el-card class="box-card" shadow="never" v-if="!isNoPluginMode">
          <template #header><div class="card-header"><span>本地配置</span></div></template>
          <el-form :model="localConfig" label-width="100px" size="small">
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="播放性能">
                  <el-select v-model="localConfig.netsPreach" id="netsPreach" placeholder="请选择" style="width: 100%;">
                    <el-option label="最短延时" value="0"></el-option>
                    <el-option label="实时性好" value="1"></el-option>
                    <el-option label="均衡" value="2"></el-option>
                    <el-option label="流畅性好" value="3"></el-option>
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="图像尺寸">
                  <el-select v-model="localConfig.wndSize" id="wndSize" placeholder="请选择" style="width: 100%;">
                    <el-option label="充满" value="0"></el-option>
                    <el-option label="4:3" value="1"></el-option>
                    <el-option label="16:9" value="2"></el-option>
                  </el-select>
                </el-form-item>
              </el-col>
            </el-row>
            <el-row :gutter="20">
                <el-col :span="12">
                    <el-form-item label="规则信息">
                        <el-select v-model="localConfig.rulesInfo" id="rulesInfo" style="width: 100%;">
                            <el-option label="启用" value="1"></el-option>
                            <el-option label="禁用" value="0"></el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="抓图文件格式">
                         <el-select v-model="localConfig.captureFileFormat" id="captureFileFormat" style="width: 100%;">
                            <el-option label="JPEG" value="0"></el-option>
                            <el-option label="BMP" value="1"></el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
            </el-row>
            <el-row :gutter="20">
                <el-col :span="12">
                    <el-form-item label="录像文件大小">
                        <el-select v-model="localConfig.packSize" id="packSize" style="width: 100%;">
                            <el-option label="256M" value="0"></el-option>
                            <el-option label="512M" value="1"></el-option>
                            <el-option label="1G" value="2"></el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="协议类型">
                        <el-select v-model="localConfig.protocolType" id="protocolType" style="width: 100%;">
                            <el-option label="TCP" value="0"></el-option>
                            <el-option label="UDP" value="2"></el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
            </el-row>
            <el-form-item label="录像保存路径">
                <el-input v-model="localConfig.recordPath" id="recordPath"><template #append><el-button size="mini" @click="clickOpenFileDlg('recordPath', 0)">浏览</el-button></template></el-input>
            </el-form-item>
            <el-form-item label="回放下载路径">
                <el-input v-model="localConfig.downloadPath" id="downloadPath"><template #append><el-button size="mini" @click="clickOpenFileDlg('downloadPath', 0)">浏览</el-button></template></el-input>
            </el-form-item>
            <el-form-item label="预览抓图路径">
                <el-input v-model="localConfig.previewPicPath" id="previewPicPath"><template #append><el-button size="mini" @click="clickOpenFileDlg('previewPicPath', 0)">浏览</el-button></template></el-input>
            </el-form-item>
            <el-form-item label="回放抓图路径">
                <el-input v-model="localConfig.playbackPicPath" id="playbackPicPath"><template #append><el-button size="mini" @click="clickOpenFileDlg('playbackPicPath', 0)">浏览</el-button></template></el-input>
            </el-form-item>
            <el-form-item label="回放剪辑路径">
                <el-input v-model="localConfig.playbackFilePath" id="playbackFilePath"><template #append><el-button size="mini" @click="clickOpenFileDlg('playbackFilePath', 0)">浏览</el-button></template></el-input>
            </el-form-item>
            <el-form-item label="设备抓图路径">
                <el-input v-model="localConfig.devicePicPath" id="devicePicPath"><template #append><el-button size="mini" @click="clickOpenFileDlg('devicePicPath', 0)">浏览</el-button></template></el-input>
            </el-form-item>

            <el-form-item>
              <el-button type="primary" @click="clickGetLocalCfg" size="small">获取</el-button>
              <el-button @click="clickSetLocalCfg" size="small">设置</el-button>
            </el-form-item>
          </el-form>
        </el-card>
         <div v-else>
            <el-alert title="无插件模式下，部分功能（如本地配置）可能不可用。" type="info" show-icon :closable="false" style="margin-bottom:15px;"></el-alert>
        </div>

        <el-card class="box-card" shadow="never" v-if="!isNoPluginMode">
          <template #header><div class="card-header"><span>设备IP解析</span></div></template>
          <el-form :model="ipParse" label-width="100px" size="small">
            <el-row :gutter="20">
                <el-col :span="12">
                    <el-form-item label="模式">
                        <el-select v-model="ipParse.deviceMode" id="devicemode" @change="changeIPMode" placeholder="请选择" style="width:100%;">
                            <el-option label="IPServer" value="1"></el-option>
                            <el-option label="HiDDNS" value="2"></el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
                 <el-col :span="12">
                    <el-form-item label="设备标识">
                        <el-input v-model="ipParse.deviceId" id="deviceid"></el-input>
                    </el-form-item>
                 </el-col>
            </el-row>
             <el-row :gutter="20">
                <el-col :span="12">
                    <el-form-item label="服务器地址">
                        <el-input v-model="ipParse.serverAddress" id="serveraddress"></el-input>
                    </el-form-item>
                </el-col>
                 <el-col :span="12">
                    <el-form-item label="端口号">
                        <el-input v-model="ipParse.serverPort" id="serverport"></el-input>
                    </el-form-item>
                 </el-col>
            </el-row>
            <el-form-item>
              <el-button type="primary" @click="clickGetDeviceIP" size="small">获取设备IP</el-button>
            </el-form-item>
          </el-form>
        </el-card>

        <el-row :gutter="15">
          <el-col :span="12">
            <el-card class="box-card info-card" shadow="never">
              <template #header><div class="card-header"><span>操作信息</span></div></template>
              <div id="opinfo" class="opinfo-box"></div>
            </el-card>
          </el-col>
          <el-col :span="12">
            <el-card class="box-card info-card" shadow="never">
              <template #header><div class="card-header"><span>事件回调信息</span></div></template>
              <div id="cbinfo" class="opinfo-box"></div>
            </el-card>
          </el-col>
        </el-row>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
export default {
  name: 'VideoPage',
  data() {
    return {
      loginForm: {
        ip: '',
        port: '',
        username: '',
        password: '',
        devicePort: '',
        rtspPort: '',
        wndNum: 2,
      },
      selectedDeviceIp: '',
      selectedChannel: '',
      localConfig: {
        netsPreach: '0',
        wndSize: '0',
        rulesInfo: '1',
        captureFileFormat: '0',
        packSize: '0',
        protocolType: '0',
        recordPath: '',
        downloadPath: '',
        previewPicPath: '',
        playbackPicPath: '',
        playbackFilePath: '',
        devicePicPath: ''
      },
      ipParse: {
        deviceMode: '1',
        serverAddress: '',
        serverPort: '7071',
        deviceId: ''
      },
      isNoPluginMode: false,
      g_iWndIndex_vue: 0,
      playbackTimes: {
        starttime: '',
        endtime: '',
        downloadstarttime: '',
        downloadendtime: ''
      },
      videoPlayerResizeObserver: null,
      // 新增：播放器控制相关状态
    playerControls: {
      volume: 50,       // 默认音量
      isMuted: false,     // 是否静音
      show: false,        // 控制栏是否显示
      actualVolumeBeforeMute: 50 // 用于取消静音时恢复音量
    },
    // 用于音量设置的隐藏input的ID (如果需要通过demo.js的clickSetVolume间接设置)
    hiddenVolumeInputId: 'hiddenPlayerVolumeInput', 
    };
  },
  mounted() {
    if (typeof window.dateFormat === 'function') {
      const szCurTime = window.dateFormat(new Date(), "yyyy-MM-dd");
      this.playbackTimes.starttime = szCurTime + " 00:00:00";
      this.playbackTimes.endtime = szCurTime + " 23:59:59";
      this.playbackTimes.downloadstarttime = szCurTime + " 00:00:00";
      this.playbackTimes.downloadendtime = szCurTime + " 23:59:59";
    } else {
      console.warn("dateFormat function is not defined globally. Using fallback.");
      const today = new Date().toISOString().split('T')[0];
      this.playbackTimes.starttime = today + " 00:00:00";
      this.playbackTimes.endtime = today + " 23:59:59";
      this.playbackTimes.downloadstarttime = today + " 00:00:00";
      this.playbackTimes.downloadendtime = today + " 23:59:59";
    }
    this.initVideoPlugin();
     // 创建隐藏的音量输入框 (如果 clickSetVolume 依赖DOM ID)
    if (!document.getElementById(this.hiddenVolumeInputId)) {
        let hiddenInput = document.createElement('input');
        hiddenInput.type = 'hidden';
        hiddenInput.id = this.hiddenVolumeInputId;
        hiddenInput.value = this.playerControls.volume.toString();
        document.body.appendChild(hiddenInput);
    }

  },
  beforeUnmount() {
    if (this.videoPlayerResizeObserver) {
      this.videoPlayerResizeObserver.disconnect();
      this.videoPlayerResizeObserver = null;
    }
    if (window.WebVideoCtrl) {
      if (this.selectedDeviceIp && typeof window.WebVideoCtrl.I_Logout === 'function') {
        //  window.WebVideoCtrl.I_Logout(this.selectedDeviceIp); // Consider if logout is needed for all logged-in devices
      }
      if (typeof window.WebVideoCtrl.I_DestroyWorker === 'function') {
        window.WebVideoCtrl.I_DestroyWorker();
      }
      if (typeof window.WebVideoCtrl.I_UnInitPlugin === 'function') {
        window.WebVideoCtrl.I_UnInitPlugin();
      }
    }
    console.log("VideoPage component unmounted/destroyed.");
  },
  methods: {
    initVideoPlugin() {
      this.$nextTick(() => {
        const pluginElement = document.getElementById('divPlugin');
        if (!pluginElement) {
          this.showTip("错误: 播放器容器 (#divPlugin) 未找到!");
          console.error("#divPlugin element not found in DOM for plugin initialization.");
          return;
        }

        let initialWidth = pluginElement.clientWidth;
        if (initialWidth <= 0) {
            initialWidth = pluginElement.parentElement ? pluginElement.parentElement.clientWidth : 600;
            if(initialWidth <=0) initialWidth = 600;
            console.warn(`pluginElement clientWidth was 0 or invalid, used parent or fallback: ${initialWidth}`);
        }
        
        // 2. 播放器窗口长宽比调整为 5:3
        const initialHeight = Math.round(initialWidth * (3 / 5));
        pluginElement.style.height = initialHeight + 'px';

        const pluginWidthForInit = initialWidth;
        const pluginHeightForInit = initialHeight;

        if (!window.WebVideoCtrl || typeof window.WebVideoCtrl.I_InitPlugin !== 'function') {
          this.showTip("错误: WebVideoCtrl SDK 未能正确加载！请检查JS文件引用。");
          return;
        }

        let iRetCheck = -2;
        if (typeof window.WebVideoCtrl.I_CheckPluginInstall === 'function') {
          iRetCheck = window.WebVideoCtrl.I_CheckPluginInstall();
        }

        if (iRetCheck === -1 &&
            (typeof window.WebVideoCtrl.I_SupportNoPlugin === 'function' && !window.WebVideoCtrl.I_SupportNoPlugin())) {
          this.showTip("您还未安装过插件！");
          return;
        }

        window.WebVideoCtrl.I_InitPlugin(pluginWidthForInit, pluginHeightForInit, {
          bWndFull: true,
          iPackageType: 2,
          iWndowType: 1,
          bNoPlugin: true,
          // 3. 关于窗口间padding: SDK的szColorProperty可能用于设置子窗口边框，
          // 这会产生视觉间距。具体增加"padding"需修改SDK或其内部q()函数。
          // szColorProperty: "sub-border:FF0000; sub-border-select:00FF00; ", // 示例：红色边框，绿色选中边框
          cbSelWnd: (xmlDoc) => {
            const wndIndexNode = xmlDoc.getElementsByTagName("SelectWnd")[0];
            if (wndIndexNode) {
              this.g_iWndIndex_vue = parseInt(wndIndexNode.textContent, 10);
              this.showCallbackInfo("当前选择窗口：" + this.g_iWndIndex_vue);
            }
          },
          cbDoubleClickWnd: (iWndIndex, bFullScreen) => {
            this.showCallbackInfo((bFullScreen ? "放大窗口：" : "还原窗口：") + iWndIndex);
          },
          cbEvent: (iEventType, iParam1, iParam2) => {
            if (iEventType === 2) this.showCallbackInfo("窗口" + iParam1 + "回放结束！");
            else if (iEventType === -1) this.showCallbackInfo("设备" + iParam1 + "网络错误！");
            else if (iEventType === 3001 && window.clickStopRecord && typeof window.g_szRecordType !== 'undefined') {
              window.clickStopRecord(window.g_szRecordType, iParam1);
            }
          },
          cbRemoteConfig: () => this.showCallbackInfo("关闭远程配置库！"),
              // 在您的 Demo.vue 的 methods -> initVideoPlugin -> cbInitPluginComplete 回调中:
    // ... （其他回调参数保持不变） ...
    cbInitPluginComplete: () => {
      const insertRet = window.WebVideoCtrl.I_InsertOBJECTPlugin("divPlugin");
      if (insertRet !== 0) {
        this.showTip("I_InsertOBJECTPlugin 插入插件失败！错误码: " + insertRet);
        console.error("I_InsertOBJECTPlugin 插入插件失败！错误码: " + insertRet);
        return;
      }
      console.log("插件对象成功插入 (cbInitPluginComplete)");

      if (typeof window.WebVideoCtrl.I_SupportNoPlugin === 'function') {
          this.isNoPluginMode = window.WebVideoCtrl.I_SupportNoPlugin();
          console.log(this.isNoPluginMode ? "当前为无插件播放模式。" : "当前为插件播放模式。");
      }

      if (typeof window.WebVideoCtrl.I_CheckPluginVersion === 'function' && !this.isNoPluginMode) {
        if (window.WebVideoCtrl.I_CheckPluginVersion() === -1) {
          this.showTip("检测到新的插件版本！");
        }
      }
      
      // 将 setWndNum 的调用也放入一个短暂的延时
      // 以确保插件在接收更改窗口分割的命令前已基本稳定
      setTimeout(() => {
        console.log(`Delayed call to setWndNum with: ${this.loginForm.wndNum}`);
        this.setWndNum(this.loginForm.wndNum); // 应该会调用 setWndNum(2)

        // 后续的 I_Resize 调用（用于修正5:3长宽比）也应该在这个延时之后，
        // 或者在其自己的延时内，确保 setWndNum 的效果已应用
        // 您当前的 I_Resize 调用已经有 $nextTick 和 setTimeout(250)，这通常是足够的。
        // 如果这里的延时解决了问题，可以考虑将 I_Resize 的延时相对于此延时调整。
        // 为简单起见，先只延迟 setWndNum。
        // （原有的 I_Resize 调用逻辑保持在下面）
      }, 50); // 尝试一个较小的延时，例如50ms或100ms

      // 这是之前为了修正长宽比和初始布局的 I_Resize 调用，保持它
      this.$nextTick(() => {
        setTimeout(() => {
          if (window.WebVideoCtrl && typeof window.WebVideoCtrl.I_Resize === 'function') {
            const currentPluginEl = document.getElementById('divPlugin');
            if (currentPluginEl) {
              const currentWidth = currentPluginEl.clientWidth;
              const targetHeight = Math.round(currentWidth * (3 / 5)); // 5:3
              currentPluginEl.style.height = targetHeight + 'px'; 
              window.WebVideoCtrl.I_Resize(currentWidth, targetHeight);
              console.log(`cbInitPluginComplete (delayed): I_Resize(${currentWidth},${targetHeight}) for 5:3 fix.`);
            }
          }
        }, 250); // 这个延时需要比上面 setWndNum 的延时更长，或者至少不冲突
      });

      if (!this.isNoPluginMode) {
        this.clickGetLocalCfg();
      } else {
        this.showTip("无插件模式，跳过获取本地配置。", "info");
      }
    }
// ... (I_InitPlugin 的其他参数和结尾) ...
        });
        
        if (pluginElement) {
            this.setupVideoPlayerResizeObserver(pluginElement);
        }
      });
    },
    setupVideoPlayerResizeObserver(elementToObserve) {
      if (this.videoPlayerResizeObserver) {
        this.videoPlayerResizeObserver.disconnect();
      }
      this.videoPlayerResizeObserver = new ResizeObserver(entries => {
        const entry = entries[0];
        if (!entry) return;

        const element = entry.target;
        const newWidth = Math.round(element.getBoundingClientRect().width);

        if (newWidth > 0) {
          const targetHeight = Math.round(newWidth * (3 / 5)); // 2. 播放器窗口长宽比调整为 5:3
          const currentHeight = Math.round(element.getBoundingClientRect().height);
          const tolerance = 2;

          if (Math.abs(currentHeight - targetHeight) > tolerance) {
            console.log(`ResizeObserver: Width: ${newWidth}. CurrentH: ${currentHeight}, TargetH: ${targetHeight}. Updating height.`);
            this.videoPlayerResizeObserver.unobserve(element);
            element.style.height = targetHeight + 'px';

            if (window.WebVideoCtrl && typeof window.WebVideoCtrl.I_Resize === 'function') {
              this.$nextTick(() => {
                setTimeout(() => {
                  if (document.body.contains(element)) {
                    window.WebVideoCtrl.I_Resize(newWidth, targetHeight);
                  }
                  if (this.videoPlayerResizeObserver && document.body.contains(element)) {
                    this.videoPlayerResizeObserver.observe(element);
                  }
                }, 50); 
              });
            } else {
              if (this.videoPlayerResizeObserver && document.body.contains(element)) {
                this.videoPlayerResizeObserver.observe(element);
              }
            }
          }
        }
      });
      this.videoPlayerResizeObserver.observe(elementToObserve);
    },
    handleVideoContainerMouseEnter() {
    this.playerControls.show = true;
    },
    handleVideoContainerMouseLeave() {
      this.playerControls.show = false;
    },
    stopCurrentWindowPreview() {
      // 这里的 clickStopRealPlay 应该是您Vue中已有的方法，
      // 它会调用 window.clickStopRealPlay()，后者作用于当前选中的窗口
      console.log(`停止预览窗口: ${this.g_iWndIndex_vue}`);
      this.clickStopRealPlay(); // 假设此方法已能正确停止当前选中窗口的预览
    },
    handleVolumeChange(newVolume) {
    console.log(`音量改变为: ${newVolume}, 当前选中窗口: ${this.g_iWndIndex_vue}`);
    this.playerControls.volume = newVolume;
    if (newVolume > 0 && this.playerControls.isMuted) {
        this.playerControls.isMuted = false; // 如果拖动滑块且有音量，则取消静音
         if (window.clickOpenSound && typeof window.clickOpenSound === 'function') {
            window.clickOpenSound(); // 打开声音
        }
    } else if (newVolume === 0 && !this.playerControls.isMuted) {
        this.playerControls.isMuted = true; // 如果滑块到0，则静音
        if (window.clickCloseSound && typeof window.clickCloseSound === 'function') {
            window.clickCloseSound(); // 关闭声音
        }
    }
    
    // 调用 demo.js 中的 clickSetVolume
    // 方式1：如果 clickSetVolume 修改为接受参数:
    // if (window.clickSetVolume && typeof window.clickSetVolume === 'function') {
    //   window.clickSetVolume(newVolume, this.g_iWndIndex_vue); // 假设可以传窗口索引
    // }
    // 方式2：通过隐藏input间接传递 (需要确保 clickSetVolume 读取这个ID)
    const hiddenVolumeEl = document.getElementById(this.hiddenVolumeInputId);
    if (hiddenVolumeEl) {
        hiddenVolumeEl.value = newVolume.toString();
    }
    // 还需要确保 demo.js 中的 clickSetVolume 函数读取正确的 ID (例如 this.hiddenVolumeInputId)
    // 或者，如果 demo.js 的 clickSetVolume 固定读取 id="volume"，那我们就用那个ID
    // 我们假设 demo.js 的 clickSetVolume 读取 id="volume"
    const demoVolumeInput = document.getElementById('volume'); // 查找原demo.html中的volume输入框ID
    if(demoVolumeInput) { // 如果原demo.html的volume输入框还存在于某处（例如被隐藏的预览模块）
        demoVolumeInput.value = newVolume.toString();
    } else { // 如果不存在，我们用我们创建的隐藏输入框
         if(hiddenVolumeEl) hiddenVolumeEl.value = newVolume.toString();
    }

    if (window.clickSetVolume && typeof window.clickSetVolume === 'function') {
        // 确保 clickSetVolume 内部知道要用哪个窗口的音量
        // 它可能默认使用 g_iWndIndex，这和 this.g_iWndIndex_vue 应该是一致的
        window.clickSetVolume(); 
    } else {
        this.showTip("错误: clickSetVolume 函数未找到", "error");
    }
    this.playerControls.actualVolumeBeforeMute = newVolume > 0 ? newVolume : this.playerControls.actualVolumeBeforeMute;
  },

  toggleMute() {
    this.playerControls.isMuted = !this.playerControls.isMuted;
    if (this.playerControls.isMuted) {
      this.playerControls.actualVolumeBeforeMute = this.playerControls.volume > 0 ? this.playerControls.volume : this.playerControls.actualVolumeBeforeMute;
      this.playerControls.volume = 0; // 滑块也归零
      if (window.clickCloseSound && typeof window.clickCloseSound === 'function') {
        window.clickCloseSound(); // 调用 demo.js 关闭声音
        this.showCallbackInfo(`窗口 ${this.g_iWndIndex_vue} 已静音`);
      } else {
        this.showTip("错误: clickCloseSound 函数未找到", "error");
      }
    } else {
      this.playerControls.volume = this.playerControls.actualVolumeBeforeMute > 0 ? this.playerControls.actualVolumeBeforeMute : 50; // 恢复之前音量或默认50
      if (window.clickOpenSound && typeof window.clickOpenSound === 'function') {
        window.clickOpenSound(); // 调用 demo.js 打开声音
        // 打开声音后，可能需要再次设置一下音量到恢复的值
        this.handleVolumeChange(this.playerControls.volume); 
        this.showCallbackInfo(`窗口 ${this.g_iWndIndex_vue} 已取消静音，音量恢复至 ${this.playerControls.volume}`);
      } else {
        this.showTip("错误: clickOpenSound 函数未找到", "error");
      }
    }
  },

  triggerFullScreen() {
    console.log("触发全屏");
    if (window.clickFullScreen && typeof window.clickFullScreen === 'function') {
      window.clickFullScreen(); // 调用 demo.js 中已有的全屏函数
    } else if (window.WebVideoCtrl && typeof window.WebVideoCtrl.I_FullScreen === 'function') {
      window.WebVideoCtrl.I_FullScreen(); // 或者直接调用SDK接口
    } else {
      this.showTip("错误: 全屏功能未实现或函数未找到", "error");
    }
  },
    showTip(szInfo, type = 'error') {
        const opinfoDiv = document.getElementById('opinfo');
        if (opinfoDiv) {
            const color = type === 'error' ? 'red' : (type === 'info' ? 'blue' : (type === 'success' ? 'green' : 'black'));
            const time = new Date().toLocaleTimeString();
            opinfoDiv.innerHTML = `<div style='color: ${color};'>[${time}] ${szInfo}</div>` + opinfoDiv.innerHTML;
        } else {
            console.log(`[${type || 'error'}] Tip:`, szInfo);
        }
    },
    showCallbackInfo(szInfo) {
        const cbinfoDiv = document.getElementById('cbinfo');
        if (cbinfoDiv) {
            const time = new Date().toLocaleTimeString();
            cbinfoDiv.innerHTML = `<div>[${time}] ${szInfo}</div>` + cbinfoDiv.innerHTML;
        } else {
            console.log("Callback Info:", szInfo);
        }
    },
    setWndNum(num) {
      this.loginForm.wndNum = num;
      if (window.WebVideoCtrl && typeof window.WebVideoCtrl.I_ChangeWndNum === 'function') {
        window.WebVideoCtrl.I_ChangeWndNum(num);
      } else {
        this.showTip("错误：改变窗口数量的函数 (I_ChangeWndNum) 未找到！");
      }
    },
    clickLogin() {
      this.syncVueDataToDOMForDemoJs();
      if (window.clickLogin && typeof window.clickLogin === 'function') {
        window.clickLogin();
      } else {
        this.showTip("错误：登录功能 (clickLogin) 未定义或不可用。");
      }
    },
    clickLogout() {
        if(window.clickLogout && typeof window.clickLogout === 'function') window.clickLogout();
        else this.showTip("错误: clickLogout 未定义");
    },
    clickGetDeviceInfo() {
        this.syncVueDataToDOMForDemoJs();
        if(window.clickGetDeviceInfo && typeof window.clickGetDeviceInfo === 'function') window.clickGetDeviceInfo();
        else this.showTip("错误: clickGetDeviceInfo 未定义");
    },
    handleDeviceChange() {
        this.syncVueDataToDOMForDemoJs();
        if(window.getChannelInfo && typeof window.getChannelInfo === 'function') window.getChannelInfo();
        if(window.getDevicePort && typeof window.getDevicePort === 'function') window.getDevicePort();
    },
    clickStartRealPlay() {
        this.syncVueDataToDOMForDemoJs();
        if(window.clickStartRealPlay && typeof window.clickStartRealPlay === 'function') window.clickStartRealPlay();
        else this.showTip("错误: clickStartRealPlay 未定义");
    },
    clickStopRealPlay() {
        if(window.clickStopRealPlay && typeof window.clickStopRealPlay === 'function') window.clickStopRealPlay();
        else this.showTip("错误: clickStopRealPlay 未定义");
    },
    setTextOverlay() {
        if(window.setTextOverlay && typeof window.setTextOverlay === 'function') window.setTextOverlay();
        else this.showTip("错误: setTextOverlay 未定义");
    },
    clickGetDigitalChannelInfo() {
        if(window.clickGetDigitalChannelInfo && typeof window.clickGetDigitalChannelInfo === 'function') window.clickGetDigitalChannelInfo();
        else this.showTip("错误: clickGetDigitalChannelInfo 未定义");
    },
    clickOpenFileDlg(id, type){
        if(window.clickOpenFileDlg && typeof window.clickOpenFileDlg === 'function') window.clickOpenFileDlg(id,type);
        else this.showTip("错误: clickOpenFileDlg 未定义");
    },
    clickGetLocalCfg() {
        if (this.isNoPluginMode) {
            this.showTip("提示：无插件模式下，本地配置功能可能不可用。", "info");
            return;
        }
        if (window.clickGetLocalCfg && typeof window.clickGetLocalCfg === 'function') {
            window.clickGetLocalCfg();
            this.$nextTick(() => {
                this.syncDOMToVueDataAfterDemoJs();
            });
        } else {
            this.showTip("错误：clickGetLocalCfg 函数未定义。");
        }
    },
    clickSetLocalCfg() {
        if (this.isNoPluginMode) {
            this.showTip("提示：无插件模式下，本地配置功能可能不可用。", "info");
            return;
        }
        this.syncVueDataToDOMForDemoJs();
        if(window.clickSetLocalCfg && typeof window.clickSetLocalCfg === 'function') window.clickSetLocalCfg();
        else this.showTip("错误: clickSetLocalCfg 未定义");
    },
    changeIPMode(value) {
        this.syncVueDataToDOMForDemoJs(); 
        if (window.changeIPMode && typeof window.changeIPMode === 'function') {
            window.changeIPMode(value);
        } else {
           this.showTip("错误：changeIPMode 函数未定义。");
        }
    },
    clickGetDeviceIP() {
        this.syncVueDataToDOMForDemoJs();
        if(window.clickGetDeviceIP && typeof window.clickGetDeviceIP === 'function') window.clickGetDeviceIP();
        else this.showTip("错误: clickGetDeviceIP 未定义");
    },
  // 在您的 Demo.vue 的 methods 对象中:

syncVueDataToDOMForDemoJs() {
  console.log("Syncing Vue data to DOM for demo.js...");

  const fieldsToSync = [
    // Login Form
    { id: 'loginip', obj: this.loginForm, key: 'ip' },
    { id: 'port', obj: this.loginForm, key: 'port' },
    { id: 'username', obj: this.loginForm, key: 'username' },
    { id: 'password', obj: this.loginForm, key: 'password' },
    { id: 'deviceport', obj: this.loginForm, key: 'devicePort' },
    { id: 'rtspport', obj: this.loginForm, key: 'rtspPort' },
    { id: 'ip', obj: this, key: 'selectedDeviceIp' }, // el-select
    { id: 'channels', obj: this, key: 'selectedChannel' }, // el-select

    // Local Config Form
    { id: 'netsPreach', obj: this.localConfig, key: 'netsPreach' },
    { id: 'wndSize', obj: this.localConfig, key: 'wndSize' },
    { id: 'rulesInfo', obj: this.localConfig, key: 'rulesInfo' },
    { id: 'captureFileFormat', obj: this.localConfig, key: 'captureFileFormat' },
    { id: 'packSize', obj: this.localConfig, key: 'packSize' },
    { id: 'protocolType', obj: this.localConfig, key: 'protocolType' },
    { id: 'recordPath', obj: this.localConfig, key: 'recordPath' },
    { id: 'downloadPath', obj: this.localConfig, key: 'downloadPath' },
    { id: 'previewPicPath', obj: this.localConfig, key: 'previewPicPath' },
    { id: 'playbackPicPath', obj: this.localConfig, key: 'playbackPicPath' },
    { id: 'playbackFilePath', obj: this.localConfig, key: 'playbackFilePath' },
    { id: 'devicePicPath', obj: this.localConfig, key: 'devicePicPath' },

    // IP Parse Form
    { id: 'devicemode', obj: this.ipParse, key: 'deviceMode' },
    { id: 'serveraddress', obj: this.ipParse, key: 'serverAddress' },
    { id: 'serverport', obj: this.ipParse, key: 'serverPort' },
    { id: 'deviceid', obj: this.ipParse, key: 'deviceId' },

    // --- Fields from HIDDEN sections (add to Vue data if you use them) ---
    // Preview Section (assuming data like this.previewSettings exists)
    // { id: 'streamtype', obj: this.previewSettings, key: 'streamtype' },
    // { id: 'volume', obj: this.previewSettings, key: 'volume' },
    // { id: 'audiochannels', obj: this.previewSettings, key: 'audiochannels' }, // el-select
    // { id: 'resolutionWidth', obj: this.previewSettings, key: 'resolutionWidth' },
    // { id: 'resolutionHeight', obj: this.previewSettings, key: 'resolutionHeight' },

    // Draw Section (assuming data like this.drawSettings exists)
    // { id: 'snapId', obj: this.drawSettings, key: 'snapId' },
    // { id: 'snapName', obj: this.drawSettings, key: 'snapName' },
    
    // PTZ Section (assuming data like this.ptzSettings exists)
    // { id: 'ptzspeed', obj: this.ptzSettings, key: 'ptzspeed' }, // el-select
    // { id: 'preset', obj: this.ptzSettings, key: 'preset' },

    // Playback Section (assuming data like this.playbackConfig exists for some, and playbackTimes for others)
    // { id: 'record_streamtype', obj: this.playbackConfig, key: 'recordStreamType' }, // el-select
    { id: 'starttime', obj: this.playbackTimes, key: 'starttime' }, // Already handled for visible
    { id: 'endtime', obj: this.playbackTimes, key: 'endtime' },     // Already handled for visible
    { id: 'downloadstarttime', obj: this.playbackTimes, key: 'downloadstarttime' }, // Already handled for visible
    { id: 'downloadendtime', obj: this.playbackTimes, key: 'downloadendtime' },   // Already handled for visible
    // { id: 'transstream', obj: this.playbackConfig, key: 'transstream', type: 'checkbox' }, // For el-checkbox

    // System Maintenance (assuming data like this.maintainSettings exists)
    // { id: 'edfpassword', obj: this.maintainSettings, key: 'edfpassword' },
    // { id: 'configFile', obj: this.maintainSettings, key: 'configFile' },
    // { id: 'upgradeFile', obj: this.maintainSettings, key: 'upgradeFile' },
  ];

  fieldsToSync.forEach(field => {
    if (!field.obj || typeof field.obj[field.key] === 'undefined') {
        // console.warn(`SyncVueToDOM: Vue data for ID '${field.id}' (obj key '${field.key}') is undefined. Skipping.`);
        return; // 如果Vue data中没有定义这个字段，则跳过
    }
    const wrapperElement = document.getElementById(field.id);
    if (wrapperElement) {
      const valueToSet = field.obj[field.key];
      let targetElement;

      if (field.type === 'checkbox') { // 特定处理 checkbox
        targetElement = wrapperElement.querySelector('input[type="checkbox"]');
        if (targetElement) {
          targetElement.checked = !!valueToSet; // 确保是布尔值
        }
      } else {
        targetElement = wrapperElement.querySelector('input:not([type="hidden"]), select'); // 查找可见的input或select
        if (targetElement) {
          targetElement.value = valueToSet;
        } else if (wrapperElement.matches('input, select')) { // 如果ID直接在input/select上
          wrapperElement.value = valueToSet;
        } else if (wrapperElement.classList.contains('el-select')) {
          // 对于el-select, v-model应该已经处理了值的同步。
          // 如果demo.js依赖于直接读取select的value属性，且上面没找到内部select，
          // jQuery的 .val() 通常能正确获取el-select的v-model值。
          // 此处主要是为了避免在尝试设置 .value 时出错。
        } else {
          // console.warn(`SyncVueToDOM: ID '${field.id}' 未找到内部input/select元素来设置值。`);
        }
      }
    } else {
      // console.warn(`SyncVueToDOM: ID '${field.id}' 的元素未在DOM中找到。`);
    }
  });
},

syncDOMToVueDataAfterDemoJs() {
  console.log("Syncing DOM (potentially updated by demo.js) back to Vue data...");

  const fieldsToRead = [
    // Local Config Form
    { id: 'netsPreach', obj: this.localConfig, key: 'netsPreach' },
    { id: 'wndSize', obj: this.localConfig, key: 'wndSize' },
    { id: 'rulesInfo', obj: this.localConfig, key: 'rulesInfo' },
    { id: 'captureFileFormat', obj: this.localConfig, key: 'captureFileFormat' },
    { id: 'packSize', obj: this.localConfig, key: 'packSize' },
    { id: 'protocolType', obj: this.localConfig, key: 'protocolType' },
    { id: 'recordPath', obj: this.localConfig, key: 'recordPath' },
    { id: 'downloadPath', obj: this.localConfig, key: 'downloadPath' },
    { id: 'previewPicPath', obj: this.localConfig, key: 'previewPicPath' },
    { id: 'playbackPicPath', obj: this.localConfig, key: 'playbackPicPath' },
    { id: 'playbackFilePath', obj: this.localConfig, key: 'playbackFilePath' },
    { id: 'devicePicPath', obj: this.localConfig, key: 'devicePicPath' },

    // Login Form (e.g., if deviceport is populated by getDevicePort from demo.js)
    { id: 'deviceport', obj: this.loginForm, key: 'devicePort' },
    
    // Playback (e.g., OSD time updated by demo.js)
    // { id: 'osdtime', obj: this.playbackTimes, key: 'osdtimeDisplayValue' } // 假设你有一个专门的data属性

    // --- Fields from HIDDEN sections (if demo.js populates them) ---
    // System Maintenance (configFile, upgradeFile might be populated by their "Browse" buttons)
    // { id: 'configFile', obj: this.maintainSettings, key: 'configFile' },
    // { id: 'upgradeFile', obj: this.maintainSettings, key: 'upgradeFile' },
  ];

  fieldsToRead.forEach(field => {
     if (!field.obj || typeof field.obj[field.key] === 'undefined') {
        // console.warn(`SyncDOMToVue: Vue data for ID '${field.id}' (obj key '${field.key}') is undefined. Skipping read.`);
        return; 
    }
    const wrapperElement = document.getElementById(field.id);
    if (wrapperElement) {
      let valueFromDOM;
      const inputElement = wrapperElement.querySelector('input:not([type="hidden"]), select');

      if (field.type === 'checkbox') { // 特定处理 checkbox
        const checkboxInputElement = wrapperElement.querySelector('input[type="checkbox"]');
        if (checkboxInputElement) {
          valueFromDOM = checkboxInputElement.checked;
        }
      } else if (inputElement) {
        valueFromDOM = inputElement.value;
      } else if (wrapperElement.matches('input, select')) {
        valueFromDOM = wrapperElement.value;
      } else {
        // console.warn(`SyncDOMToVue: ID '${field.id}' 未找到内部input/select元素来读取值。`);
        return; 
      }
      
      if (typeof valueFromDOM !== 'undefined' && field.obj[field.key] !== valueFromDOM) {
        field.obj[field.key] = valueFromDOM;
        // console.log(`SyncDOMToVue: ID '${field.id}' 的值已同步到Vue data: '${valueFromDOM}'`);
      }
    } else {
      // console.warn(`SyncDOMToVue: ID '${field.id}' 的元素未在DOM中找到。`);
    }
  });

  // 对于 <select id="ip"> 和 <select id="channels"> (已登录设备和通道列表)
  // demo.js 中的 getChannelInfo() 会直接操作DOM来添加 <option> 标签。
  // 这是与Vue数据驱动方式冲突最大的地方。
  // 理想情况下，getChannelInfo 应该返回一个设备列表/通道列表数组，
  // 然后Vue用这些数组来更新 this.deviceListOptions 和 this.channelListOptions (假设的data属性)，
  // <el-select> 再通过 v-for 渲染这些选项。
  // 
  // 临时的兼容：如果只是为了读取当前选中的值（v-model应该处理），
  // 并且 demo.js 在添加完选项后通过 $("#ip").val(szDeviceIdentify) 设置了选中项，
  // 那么 jQuery("#ip").val() 应该能读到。
  // 如果您发现 v-model (this.selectedDeviceIp / this.selectedChannel) 没有更新，
  // 可能需要在 getChannelInfo() 执行后，手动从DOM读取 select 的 value 并赋给 v-model。
  const ipSelect = document.getElementById('ip');
  if (ipSelect && this.selectedDeviceIp !== ipSelect.value) {
      // this.selectedDeviceIp = ipSelect.value; // 直接赋值可能导致死循环或意外的change事件
      // 更安全的方式是，确保 getChannelInfo 执行后能触发 el-select 的 'change' 事件，
      // 或者提供一个Vue可以调用的回调来更新 selectedDeviceIp。
      // 如果 getChannelInfo 仅仅是改变了 DOM select 的 value，Vue v-model 可能不会自动同步。
      // 考虑在 handleDeviceChange 中，如果是由 demo.js 引起的改变，可能需要额外处理。
  }
}
  },
  watch: {
    // 'playbackTimes.starttime'(newValue){ /* ... */ },
  }
};
</script>

<style scoped>
.outer-container {
  height: 100vh;
  font-size: 14px;
}
.simulated-sidebar {
  height: 100vh; 
  background-color: #f0f2f5;
  color: #303133;
  border-right: 1px solid #DCDFE6;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding-top: 20px;
}
.simulated-sidebar p {
    margin: 5px 0;
}
.main-content-container {
  height: 100vh;
  overflow: hidden; /* 防止主内容区自身出现滚动条，让el-main控制滚动 */
}
.left-panel-aside {
  padding: 15px;
  border-right: 1px solid #E4E7ED;
  background-color: #F5F7FA;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.right-panel-main {
  padding: 15px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}
.box-card {
  margin-bottom: 15px;
  border: 1px solid #E4E7ED;
  flex-shrink: 0; /* 防止卡片被压缩 */
}
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-weight: bold;
  font-size: 1.05em;
}
.digitaltdiv {
  border: 1px solid #EBEEF5;
  padding: 5px;
  min-height: 100px;
  max-height: 300px;
  overflow-y: auto;
}
.digitalchannellist {
  width: 100%;
  border-collapse: collapse;
}
.digitalchannellist th {
    background-color: #fafafa;
    font-weight: bold;
    text-align: left;
}
.digitalchannellist td,
.digitalchannellist th {
  border: 1px solid #EBEEF5;
  padding: 6px 8px;
  font-size: 0.9em;
}
.login-card .el-form-item {
  margin-bottom: 18px;
}
.login-card .el-input, 
.login-card .el-select .el-input {
    max-width: 260px; 
}
.login-card .el-button-group .el-button {
    padding: 8px 12px;
}
.info-card .opinfo-box {
  height: 180px;
  border: 1px solid #E4E7ED;
  padding: 10px;
  overflow-y: auto;
  font-size: 12px;
  line-height: 1.6;
  background-color: #fdfdfd;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.info-card .opinfo-box div {
    margin-bottom: 4px;
    padding-bottom: 2px;
    border-bottom: 1px dashed #f0f0f0;
}
.info-card .opinfo-box div:last-child {
    border-bottom: none;
}
.plugin { /* 修改原 .plugin 样式，移除 margin-bottom */
  width: 100%; 
  border: 1px solid #DCDFE6;
  background-color: #000000;
  /* height 由JS控制以保持长宽比 */
  flex-shrink: 0; 
  min-height: 150px;
  /* margin-bottom: 15px; /* 移动到 wrapper 上 */
}
.el-form-item .el-button + .el-button,
.el-form-item .el-button-group + .el-button,
.el-form-item .el-button + .el-button-group {
  margin-left: 10px;
}
.el-select {
    width: 100%;
}
.el-card ::v-deep .el-card__header {
    padding: 12px 15px;
    background-color: #fafbfc;
}
.el-form-item__label {
    padding-right: 10px;
}
/* 针对 Element UI input append/prepend 的按钮大小 */
.el-input-group__append .el-button,
.el-input-group__prepend .el-button {
    font-size: 12px; /* 确保按钮内字体不会过大 */
    padding: 7px 10px; /* 调整padding使其看起来更协调 */
}
.el-input-group__append, .el-input-group__prepend {
    background-color: #F5F7FA; /* 与其他按钮背景色协调 */
}
.video-player-wrapper {
  position: relative; /* 作为控制栏绝对定位的参照 */
  width: 100%; /* 与 #divPlugin 宽度一致 */
  /* 高度由 #divPlugin 决定 */
  margin-bottom: 15px; /* 与原 #divPlugin 的 margin-bottom 一致 */
}
.player-controls-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 40px; /* 控制栏高度 */
  background-color: rgba(0, 0, 0, 0.6); /* 半透明黑色背景 */
  display: flex;
  align-items: center;
  padding: 0 10px;
  box-sizing: border-box;
  z-index: 10; /* 确保在播放器内容之上 */
}

.control-button {
  color: #FFF !important; /* Element UI 图标按钮颜色 */
  font-size: 20px !important; /* 图标大小 */
  padding: 5px !important;
}
.control-button:hover {
  color: #409EFF !important; /* 悬停颜色 */
}
.volume-control {
  display: flex;
  align-items: center;
  margin-left: 10px;
  margin-right: 15px;
  min-width: 150px; /* 给音量控制一个最小宽度 */
}

.volume-slider {
  width: 100px; /* 滑块长度 */
  margin-left: 8px;
}
/* 覆盖el-slider默认样式以适应深色背景 */
.player-controls-bar .el-slider__bar {
  background-color: #409EFF;
}
.player-controls-bar .el-slider__button {
  border-color: #409EFF;
  width: 12px;
  height: 12px;
}
.player-controls-bar .el-slider__runway {
  background-color: #555;
}


/* Element UI transition fade */
.el-fade-in-linear-enter-active, .el-fade-in-linear-leave-active {
  transition: opacity .2s linear;
}
.el-fade-in-linear-enter, .el-fade-in-linear-leave-to {
  opacity: 0;
}
</style>